<!-- 上传单个文件 -->
<template>
  <div
    class="upload-file"
    v-loading="loading"
    :element-loading-text="loadingText"
  >
    <!-- 显示上传了的文件 -->
    <div class="file-show" v-if="modelValue && modelValue.id">
      <div class="image-show-content" v-if="isImage(modelValue.url!)">
        <el-image :id="elImageId" ref="elImageRef" :src="modelValue.url" fit="contain" class="img-file" />
      </div>
      <div class="file-show-content" v-else>
        <el-icon><DocumentChecked /></el-icon>
        <div class="title" v-if="modelValue && modelValue.name">
          {{ modelValue.name }}
        </div>
      </div>
      <div class="operate">
        <div class="preview-icon" @click="previewImage" v-if="modelValue?.url && isImage(modelValue.url)">
          <el-icon>
            <View />
          </el-icon>
        </div>
        <div class="download-icon" @click="downloadFileOperate">
          <el-icon>
            <Download />
          </el-icon>
        </div>
        <div class="delete-icon" @click="removeFile">
          <el-icon>
            <Delete />
          </el-icon>
        </div>
      </div>
    </div>
    <!-- 上传控件 -->
    <el-upload
      v-else
      class="upload-file-container"
      drag
      :show-file-list="false"
      :http-request="uploadFile"
      :accept="accept"
    >
      <el-icon class="el-icon--upload">
        <upload-filled />
      </el-icon>
      <div class="el-upload__text">拖拽到此上传或者<em>点击上传</em></div>
    </el-upload>
    <PreviewImage ref="previewImageRef" />
  </div>
</template>
<script setup lang="ts">
import { ElMessage, UploadRequestHandler, UploadRequestOptions, vLoading } from "element-plus";
import { uploadFileApi, deleteFileApi, IUploadFile } from '@/global/api/common';
import { UploadFilled, DocumentChecked, Delete, Download, View } from "@element-plus/icons-vue";
import { downloadFile, isImage } from "@/global/utils/common";
import PreviewImage from '@/components/base-ui/preview-image/index.vue'

const elImageId = ref('dyElImageId')

const props = defineProps<{
  modelValue: IUploadFile | undefined,
  accept?: string
}>()
const emits = defineEmits([`update:modelValue`, `change`])

// 加载中 变量
const loading = ref(false)
const loadingText = ref('正在上传，请稍等...')
// 文件信息
const fileInfo = ref<IUploadFile>({})
/**
 * 上传文件
 */
const uploadFile: UploadRequestHandler = (options: UploadRequestOptions) => new Promise((resolve, reject) => {
  let file = options.file
  let sendData = new FormData()
  sendData.append('file', file)
  if (props.accept?.includes('.pdf')) {
    if (file.type !== 'application/pdf') {
      ElMessage.error('只能上传pdf格式的文件'); //限制文件类型
      reject(false)
      return false;
    } 
  }
  loading.value = true
  uploadFileApi(sendData).then((res: KeyValue) => {
    // frontUpload 判断是不是进入页面后新上传的
    emits('update:modelValue', { ...res.data, frontUpload: true })
    emits('change', `upload`, { ...res.data, frontUpload: true })
  }).finally(() => {
    loading.value = false
  })
});
/**
 * 软删除文件
 */
let deleteMenu: IUploadFile[] = []
/**
 * 移除文件
 * （
 *   软删除 在当前显示去除掉文件的显示 
 *   将移除的文件放入deleteMenu 之后可以调用treuToDelete进行真实删除
 * ）
 */
const removeFile = () => {
  if (props.modelValue && props.modelValue.url) {
    deleteMenu.push(props.modelValue)
    emits('update:modelValue', {})
    emits('change', `delete`)
  }
}
/**
 * 预览文件
 */
const previewImageRef = ref<InstanceType<typeof PreviewImage>>()
const previewImage = () => {
  props.modelValue && props.modelValue.url && previewImageRef.value?.open(props.modelValue.url)
}
/**
 * 下载文件
 */
const downloadFileOperate = () => {
  props.modelValue && props.modelValue.url && downloadFile(props.modelValue.url)
}
/**
 * 真实删除（彻底删除文件）
 */
let isTreuToDelete = false
const trueToDelete = () => {
  isTreuToDelete = true
  deleteMenu.forEach(item => {
    deleteFile(item)
  })
  deleteMenu = []
}

/**
 * (刷新、重新打开网站)退出页面时清除无用文件
 * frontUpload 如果是回显（不是新上传的）的文件 那么必不可能有
 */
let runBeforeunloadFunc = false
const beforeunloadFunc = () => {
  if (!runBeforeunloadFunc) {
    runBeforeunloadFunc = true
    let arr: IUploadFile[] = JSON.parse(JSON.stringify(deleteMenu))
    deleteMenu = []
    arr.forEach(item => {
      if (item && item.frontUpload) {
        deleteFile(item)
      }
    })
    if (props.modelValue && props.modelValue.frontUpload) {
      deleteFile(props.modelValue)
    }
  }
}
onUnmounted(() => {
  elImageId.value = `dyElImageId${new Date().valueOf()}`
  window.removeEventListener("beforeunload", beforeunloadFunc, false)
  if (!isTreuToDelete) {
    beforeunloadFunc()
  } else {
    isTreuToDelete = false
  }
})
window.addEventListener("beforeunload", beforeunloadFunc, false)

/**
 * 删除文件方法
 */
const deleteFile = (item: IUploadFile) => new Promise((resolve, reject) => {
  let sendData: KeyValue = {
    n: true
  }
  if (item.url) {
    sendData.url = item.url
  }
  if (item.url && item.baseUrl) {
    sendData.url = item.baseUrl + item.url
  }
  if (item.path) {
    sendData.path = item.path
  }
  if (item.path && item.baseUrl) {
    sendData.path = item.baseUrl + item.path
  }
  if (item.id) {
    sendData.id = item.id
  }
  deleteFileApi(sendData).then(() => {
    resolve(true)
  }).catch(() => {
    reject()
  })
})

defineExpose({ trueToDelete })
</script>
<style scoped lang="scss">
  .upload-file {
    width: 100%;
    height: 100%;
    position: relative;
    .upload-file-container {
      width: 100%;
      height: 100%;
      .is-drag {
        width: 100%;
        height: 100%;
      }
    }
    .file-show {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      border: 1px solid var(--el-border-color);
      > .image-show-content {
        width: 100%;
        height: 100%;
        box-sizing: border-box;
        padding: 10px;
        > .img-file {
          width: 100%;
          height: 100%;
          object-fit: contain;
        }
      }
      .file-show-content {
        position: relative;
        text-align: center;
        font-size: 40px;
        .title {
          margin-top: 10px;
          font-size: 16px;
          font-weight: bold;
        }
      }
      .operate {
        background-color: rgba($color: #000000, $alpha: .5);
        opacity: 0;
        width: 100%;
        height: 100%;
        position: absolute;
        left: 0;
        top: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: all .3s;
        .preview-icon {
          width: 35px;
          height: 35px;
          border-radius: 50%;
          display: flex;
          align-items: center;
          justify-content: center;
          color: #ffffff;
          font-size: 18px;
          cursor: pointer;
          transition: all .3s;
          background-color: #6db8fa;
          margin-right: 20px;
          &:hover {
            background-color: #0044ff;
          }
        }

        .delete-icon {
          width: 35px;
          height: 35px;
          border-radius: 50%;
          display: flex;
          align-items: center;
          justify-content: center;
          color: red;
          font-size: 18px;
          cursor: pointer;
          transition: all .3s;
          background-color: #ebc5c5;
          &:hover {
            background-color: #e38f8f;
          }
        }
        .download-icon {
          width: 35px;
          height: 35px;
          border-radius: 50%;
          display: flex;
          align-items: center;
          justify-content: center;
          color: var(-el-color-primary);
          font-size: 18px;
          cursor: pointer;
          transition: all .3s;
          background-color: rgb(120, 247, 120);
          margin-right: 20px;
            &:hover {
              background-color: #00b96e;
            }
        }
      }
      &:hover {
        .operate {
          opacity: 1;
        }
      }
    }
  }
</style>
<style lang="scss">
  .upload-file {
    .upload-file-container {
      .is-drag {
        width: 100%;
        height: 100%;
        .el-upload-dragger {
          width: 100%;
          height: 100%;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
        }
      }
    }
  }
</style>
